/* --- class without pointer mumber ---*/
#ifndef __MYCOMPLEX__ // 防卫式声明，减少重复include，可以使用#pragma once
#define __MYCOMPLEX__

#include <iostream>
using namespace std;

// 前置声明 forward declarations
class complex;

complex& __doapl(complex* ths, const complex& r);
complex& __doami(complex* ths, const complex& r);
complex& __doaml(complex* ths, const complex& r);


// 类声明 class declarations
class complex { // class head
private:
    double re, im;

    // 友元，打破了封装，下面的函数可以自由取得friend的private成员
    // 相同class的各个objects互为friend友元
    friend complex& __doapl(complex*, const complex&);
    friend complex& __doami(complex*, const complex&);
    friend complex& __doaml(complex*, const complex&);

public:
    // 列初始化，比赋值效率高
    complex(double r = 0, double i = 0) : re(r), im(i) {
        cout << "complex(double r = 0, double i = 0) : re(r), im(i)" << endl;
    }

    complex() { // 没有被调用过
        cout << "complex()" << endl;
    }
    
    // 在class body内声明，在body外定义
    complex& operator+=(const complex&);
    complex& operator-=(const complex&);
    complex& operator*=(const complex&);
    complex& operator/=(const complex&);

    // real()和imag()函数在此直接定义
    // 函数若在class body内定义完成，便自动成为inline候选人，无需再在前面添加inline，是否成为inline还得看编译器
    // 常量成员函数，如果不修改data值则用const
    double real() const {return re;}
    double imag() const {return im;}
};

// 类定义 class definition

inline complex& __doapl(complex* ths, const complex& r) {
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}

inline complex& complex::operator+=(const complex& r) {
    return __doapl(this, r);
}

inline complex& __doami(complex* ths, const complex& r) {
    ths->re -= r.re;
    ths->im -= r.im;
    return *ths;
}

inline complex& complex::operator-=(const complex& r) {
    return __doami(this, r);
}

inline complex& __doaml(complex* ths, const complex& r) {
    double f = ths->re * r.re - ths->im * r.im;
    ths->im = ths->re * r.im + ths->im * r.re;
    ths->re = f;
    return *ths;
}

inline complex& complex::operator*=(const complex& r) {
    return __doaml(this, r);
}

// inline只是对编译器的建议，不在class body内的想要inline，需要手动添加
inline double imag(const complex& x) {
    return x.imag();
}

inline double real(const complex& x) {
    return x.real();
}

// 非成员函数的操作符重载，没有this
// 下面这些函数绝不可return by reference，因为它们返回的必定是个local object，都是返回一个临时对象typename()匿名对象
inline complex operator+(const complex& x, const complex& y) {
    return complex(real(x) + real(y), imag(x) + imag(y));
}

inline complex operator+(const complex& x, double y) {
    return complex(real(x) + y, imag(x));
}

inline complex operator+(double x, const complex& y) {
    return complex(x + real(y), imag(y));
}

inline complex operator-(const complex& x, const complex& y) {
    return complex(real(x) - real(y), imag(x) - imag(y));
}

inline complex operator-(const complex& x, double y) {
    return complex(real(x) - y, imag(x));
}

inline complex operator-(double x, const complex& y) {
    return complex(x - real(y), -imag(x));
}

inline complex operator * (const complex& x, const complex& y){
    return complex(real(x) * real(y) - imag(x) * imag(y),
			   real(x) * imag(y) + imag(x) * real(y));
}

inline complex operator*(const complex& x, double y){
    return complex(real(x) * y, imag(x) * y);
}

inline complex operator*(double x, const complex& y)
{
    return complex(x * real(y), x * imag(y));
}

complex operator/(const complex& x, double y) {
    return complex(real(x) / y, imag(x) / y);
}

inline complex operator+(const complex& x) {
    return x;
}

inline complex operator-(const complex& x) {
    return complex(-real(x), -imag(x));
}


// copy paste
inline bool
operator == (const complex& x, const complex& y)
{
  return real (x) == real (y) && imag (x) == imag (y);
}

inline bool
operator == (const complex& x, double y)
{
  return real (x) == y && imag (x) == 0;
}

inline bool
operator == (double x, const complex& y)
{
  return x == real (y) && imag (y) == 0;
}

inline bool
operator != (const complex& x, const complex& y)
{
  return real (x) != real (y) || imag (x) != imag (y);
}

inline bool
operator != (const complex& x, double y)
{
  return real (x) != y || imag (x) != 0;
}

inline bool
operator != (double x, const complex& y)
{
  return x != real (y) || imag (y) != 0;
}

#include <cmath>

inline complex
polar (double r, double t)
{
  return complex (r * cos (t), r * sin (t));
}

inline complex
conj (const complex& x) 
{
  return complex (real (x), -imag (x));
}

inline double
norm (const complex& x)
{
  return real (x) * real (x) + imag (x) * imag (x);
}

#endif // __MYCOMPLEX__